package com.siyoumi.app.modules.act.service;

import com.siyoumi.app.entity.*;
import com.siyoumi.app.modules.prize.service.SvcSysPrizeSet;
import com.siyoumi.app.sys.service.prize.PrizeSend;
import com.siyoumi.app.service.*;
import com.siyoumi.component.XApp;
import com.siyoumi.component.XRedis;
import com.siyoumi.component.XRedisLock;
import com.siyoumi.component.XSpringContext;
import com.siyoumi.component.http.InputData;
import com.siyoumi.component.http.XHttpContext;
import com.siyoumi.exception.EnumSys;
import com.siyoumi.mybatispuls.JoinWrapperPlus;
import com.siyoumi.service.IWebService;
import com.siyoumi.util.XLog;
import com.siyoumi.util.XReturn;
import com.siyoumi.util.XSqlStr;
import com.siyoumi.util.XStr;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class SvcActSet
        implements IWebService {
    static public SvcActSet getBean() {
        return XSpringContext.getBean(SvcActSet.class);
    }

    static public ActSetService getApp() {
        return ActSetService.getBean();
    }


    /**
     * 获取活动配置
     *
     * @param actId
     */
    public ActSet getEntity(String actId) {
        String key = getApp().getEntityCacheKey(actId);
        ActSet entityAct = XRedis.getBean().getAndSetData(key, k -> {
            return SvcActSet.getApp().getEntity(actId);
        }, ActSet.class);

        return entityAct;
    }

    /**
     * 获取活动属性
     *
     * @param actId
     */
    public Map<String, String> getAppendData(String actId) {
        String key = getApp().getEntityCacheKey(actId + "|append");

        ActSet entityAct = getEntity(actId);

        Map<String, String> mapData = XRedis.getBean().getAndSetData(key, k -> {
            if (XStr.isNullOrEmpty(entityAct.getAset_item_id())) {
                return null;
            }
            SysItemData entityData = SysItemDataService.getBean().getEntityByKey(entityAct.getAset_item_id(), entityAct.getKey());
            if (entityData == null) {
                return null;
            }
            return entityData.data();
        }, Map.class);

        if (mapData == null) {
            mapData = new HashMap<>();
        }

        return mapData;
    }

    /**
     * 发起
     *
     * @param actId
     * @param key
     */
    public XReturn launch(String actId, String key) {
        //ActDataLaunchService appLaunch = ActDataLaunchService.getBean();
        //ActDataLaunch entityLaunch = appLaunch.getOrNewEntity(actId, key, getOpenid());

        XReturn r = XReturn.getR(0);
        //r.setData("entity_launch", entityLaunch);

        return r;
    }

    public XReturn chouBug(String actId, String openid, String psetId) {
        ActDataChouService appChou = ActDataChouService.getBean();

        ActSet entityAct = getEntity(actId);
        if (entityAct == null) {
            return EnumSys.ERR_VAL.getR("活动ID异常");
        }
        SysPrizeSet entityPrizeSet = SysPrizeSetService.getBean().getEntity(psetId);

        String winKey = entityPrizeSet.getKey() + "|" + openid;
        ActDataChou entityChouWin = appChou.getEntityByWinKey(actId, winKey);
        if (entityChouWin != null) {
            XLog.info(this.getClass(), "已中过");
            return XReturn.getR(20106, "用户已中过此奖品");
        }

        ActDataChou entityChou = new ActDataChou();
        entityChou.setAdc_x_id(XHttpContext.getX());
        entityChou.setAdc_actset_id(entityAct.getAset_id());
        entityChou.setAdc_openid(openid);
        entityChou.setAdc_uix(XApp.getStrID());
        entityChou.setAutoID();
        entityChou.setAdc_prize_id(psetId);
        //key
        entityChou.setAdc_win_uix(winKey);
        appChou.save(entityChou);

        XLog.info(this.getClass(), "中奖，扣减库存");
        SysStockService.getBean().subStock(entityPrizeSet.getKey(), 1L);

        XLog.info(this.getClass(), "中奖，进行发奖");
        PrizeSend appPrize = PrizeSend.getBean(entityPrizeSet);
        XReturn r = appPrize.send(entityChou.getKey(), entityChou.getAdc_openid());
        if (r.ok()) {
            r.setErrMsg("派奖成功");
        }

        return r;
    }

    public XReturn chouLock(String actId, String chouKey) {
        String lockKey = XStr.concat(actId, ":", getOpenid());
        return XRedisLock.lockFunc(lockKey, k -> chou(actId, chouKey), -1);
    }

    /**
     * 抽奖
     */
    public XReturn chou(String actId, String chouKey) {
        ActDataChouService appChou = ActDataChouService.getBean();
        ActDataChou entityChou = appChou.getEntity(actId, chouKey);
        if (entityChou != null) {
            return XReturn.getR(20054, "已抽过");
        }

        XLog.info(this.getClass(), "开始抽奖");
        XLog.info(this.getClass(), "随机抽出1个奖品");
        //
        ActSet entityAct = getEntity(actId);
        SysPrizeSetChou entityPrizechou = getPrizeChouRand(actId);
        if (entityPrizechou != null) {
            XLog.info(this.getClass(), "中奖，进行中奖规则判断");
            if (entityAct.getAset_win_multi() == 0) {
                XLog.info(this.getClass(), "整个活动只能中1次奖");
                Boolean win = appChou.win(actId, getOpenid());
                if (win) {
                    XLog.info(this.getClass(), "已中过");
                    entityPrizechou = null;
                }
            } else {
                XLog.info(this.getClass(), "整个活动可以多次中奖，但1个奖品只能中1次");
                String winKey = entityPrizechou.getKey() + "|" + getOpenid();
                ActDataChou entityChouWin = appChou.getEntityByWinKey(actId, winKey);
                if (entityChouWin != null) {
                    XLog.info(this.getClass(), "已中过");
                    entityPrizechou = null;
                }
            }
        }


        SysPrizeSetChou entityPrizechouTrue = entityPrizechou;

        TransactionTemplate transaction = XApp.getTransaction();
        return transaction.execute(status -> {
            ActDataChou entityChouNew = new ActDataChou();
            entityChouNew.setAdc_x_id(XHttpContext.getX());
            entityChouNew.setAdc_actset_id(entityAct.getAset_id());
            entityChouNew.setAdc_openid(getOpenid());
            entityChouNew.setAdc_uix(chouKey);
            entityChouNew.setAutoID();

            if (entityPrizechouTrue != null) {
                entityChouNew.setAdc_prize_id(entityPrizechouTrue.getKey());

                XLog.info(this.getClass(), "锁库存");
                SysStock entityStock = SysStockService.getBean().getEntityBySrc(entityPrizechouTrue.getKey(), true);

                String winKey = entityPrizechouTrue.getKey() + "|" + getOpenid();
                XReturn r = entityPrizechouTrue.compareWin();
                if (r.ok()) {
                    XLog.info(this.getClass(), "中奖");
                } else {
                    XLog.info(this.getClass(), "不中奖，清掉中奖key");
                    winKey = null;
                }
                if (entityStock.getStock_count_left() <= 0) {
                    XLog.info(this.getClass(), "不中奖，库存不足");
                    winKey = null;
                }
                entityChouNew.setAdc_win_uix(winKey);
            }

            try {
                appChou.save(entityChouNew);
            } catch (Exception ex) {
                XLog.error(this.getClass(), "并发同时中奖，只允许1个人中");
                entityChouNew.setAdc_win_uix(null);
                appChou.save(entityChouNew);
            }

            XReturn r = XReturn.getR(0);
            r.setData("entity_prize", null);

            if (XStr.hasAnyText(entityChouNew.getAdc_win_uix())) {
                XLog.info(this.getClass(), "中奖，扣减库存");
                SysStockService.getBean().subStock(entityPrizechouTrue.getKey(), 1L);

                SysPrizeSet entityPrizeSet = SysPrizeSetService.getBean().getEntity(entityPrizechouTrue.getKey());
                XLog.info(this.getClass(), "中奖，进行发奖");
                PrizeSend appPrize = PrizeSend.getBean(entityPrizeSet);
                r = appPrize.send(entityChouNew.getKey(), entityChouNew.getAdc_openid());

                r.setData("pset_str_00", entityPrizeSet.getPset_str_00());
            }
            return r;
        });
    }

    /**
     * select
     *
     * @return query
     */
    public JoinWrapperPlus<ActSet> listQuery(InputData inputData) {
        String name = inputData.input("name");

        JoinWrapperPlus<ActSet> query = SvcActSet.getApp().join();
        query.eq("aset_x_id", XHttpContext.getX())
                .eq("aset_del", 0)
                .orderByAsc("aset_order")
                .orderByDesc("aset_create_date");
        if (XStr.hasAnyText(name)) { // 名称
            query.like("aset_name", name);
        }

        return query;
    }

    /**
     * 奖品列表
     *
     * @param actId
     */
    public List<SysPrizeSet> listPrize(String actId) {
        InputData inputData = InputData.getIns();
        inputData.put("id_src", actId);
        JoinWrapperPlus<SysPrizeSet> query = SvcSysPrizeSet.getBean().listQuery(inputData);
        return SvcSysPrizeSet.getApp().get(query);
    }


    /**
     * 删除
     *
     * @param ids
     * @return
     */
    public XReturn delete(List<String> ids) {
        XReturn r = XReturn.getR(0);

        InputData inputData = InputData.getIns();
        JoinWrapperPlus<ActSet> query = listQuery(inputData);
        query.in("aset_id", ids);

        List<ActSet> list = getApp().get(query);
        for (ActSet entity : list) {
            getApp().delete(entity.getKey());
        }

        return r;
    }

    /**
     * 删除测试数据
     *
     * @param actId
     */
    @Transactional(propagation = Propagation.MANDATORY)
    public XReturn deleteTestData(String actId) {
        ActSet entityAct = getEntity(actId);
        if (entityAct == null) {
            return EnumSys.ERR_VAL.getR("act_id 异常");
        }
        if (!entityAct.test()) {
            return XReturn.getR(20255, "正式环境，不能删除");
        }

        //发起数据
        ActDataLaunchService appLaunch = ActDataLaunchService.getBean();
        JoinWrapperPlus<ActDataLaunch> queryLaunch = appLaunch.join();
        queryLaunch.eq("adl_actset_id", entityAct.getKey());
        appLaunch.mapper().delete(queryLaunch);

        //参与数据
        ActDataService appData = ActDataService.getBean();
        JoinWrapperPlus<ActData> queryData = appData.join();
        queryLaunch.eq("adata_actset_id", entityAct.getKey());
        appData.mapper().delete(queryData);

        //抽奖记录
        ActDataChouService appChou = ActDataChouService.getBean();
        JoinWrapperPlus<ActDataChou> queryChou = appChou.join();
        queryChou.eq("adc_actset_id", entityAct.getKey());
        appChou.mapper().delete(queryChou);

        //库存回退
        List<SysPrizeSet> listPrizeSet = listPrize(entityAct.getKey());
        for (SysPrizeSet entityPrizeSet : listPrizeSet) {
            SysStock entityStock = SysStockService.getBean().getEntityBySrc(entityPrizeSet.getKey(), false);
            SysStockService.getBean().subStock(entityPrizeSet.getKey(), -entityStock.getStock_count_use());
        }

        return XReturn.getR(0);
    }


    protected JoinWrapperPlus<SysPrizeSetChou> getPrizeChouRandQuery(String actId) {
        JoinWrapperPlus<SysPrizeSetChou> query = SysPrizeSetChouService.getBean().join();
        //
        query.join(SysStock.table(), "stock_id_src", "pschou_id");
        query.eq("pschou_x_id", XHttpContext.getX())
                .eq("pschou_id_src", actId)
                .gt("pschou_win_rate", 0)
                .gt("stock_count_left", 0);
        return query;
    }

    /**
     * 随机抽一个奖品
     */
    protected SysPrizeSetChou getPrizeChouRand(String actId) {
        XLog.info(this.getClass(), "随机抽一个奖品");
        SysPrizeSetChouService appPrizeChou = SysPrizeSetChouService.getBean();
        JoinWrapperPlus<SysPrizeSetChou> query = getPrizeChouRandQuery(actId);
        Long count = appPrizeChou.count(query);
        if (count <= 0) {
            return null;
        }

        int rnd = XApp.random(0, count.intValue() - 1);
        JoinWrapperPlus<SysPrizeSetChou> queryFirst = getPrizeChouRandQuery(actId);
        queryFirst.last(XSqlStr.limitX(1, rnd));
        XLog.info(this.getClass(), "总数：", count, "，随机数：" + rnd);
        List<SysPrizeSetChou> listPrizeSetChou = appPrizeChou.get(queryFirst);
        return listPrizeSetChou.get(0);
    }
}
